#include "path_utils.hpp"
#include <filesystem>

namespace fs = std::filesystem;

static void platformGetBinaryPath(char *buffer, size_t buff_length);

namespace Utils {

    std::string GetAppDirPath() {
        static char s_path[512]{ 0 };
        if (s_path[0] == 0) {
            platformGetBinaryPath(s_path, std::size(s_path));
        }
        return s_path;
    }

    std::string GetShadersDirPath() {
        static char s_path[512]{ 0 };
        if (s_path[0] == 0) {
            auto str_path = (fs::path{ GetAppDirPath() } / "shaders").string();
            memcpy(s_path, str_path.data(), str_path.length());
        }
        return s_path;
    }

    std::string GetDataDirPath() {
        static char s_path[512]{ 0 };
        if (s_path[0] == 0) {
            auto str_path = (fs::path{ GetAppDirPath() } / "data").string();
            memcpy(s_path, str_path.data(), str_path.length());
        }
        return s_path;
    }

    std::string GetFontDirPath() {
        static char s_path[512]{ 0 };
        if (s_path[0] == 0) {
            auto str_path = (fs::path{ GetAppDirPath() } / "fonts").string();
            memcpy(s_path, str_path.data(), str_path.length());
        }
        return s_path;
    }

    std::string GetAssetDirPath() {
        static char s_path[512]{ 0 };
        if (s_path[0] == 0) {
            auto str_path = (fs::path{ GetAppDirPath() } / "assets").string();
            memcpy(s_path, str_path.data(), str_path.length());
        }
        return s_path;
    }

}

#if defined(WIN32)

#include "win32_utility.hpp"
#include <ShlObj.h>
#include <Shlwapi.h>

void platformGetBinaryPath(char *buffer, size_t buff_length) {
    wchar_t buff[MAX_PATH + 1]{ 0 };
    GetModuleFileNameW(nullptr, buff, MAX_PATH);
    PathRemoveFileSpecW(buff);
    std::string u8Path = Win32::toUtf8(buff);
    memcpy(buffer, u8Path.data(), u8Path.length());
    buff[u8Path.length()] = 0;
}

#elif defined(__unix__)

#include <libgen.h>
#include <unistd.h>

void platformGetBinaryPath(char *buffer, size_t buff_length) {
    readlink("/proc/self/exe", buffer, buff_length);
    dirname(buffer);
}

#else
#error "Code Not Ported Yet!!"
#endif
